package com.heartunderblade.rpc.protocol;

import com.heartunderblade.rpc.ErrorCode.ErrorCode;
import com.heartunderblade.rpc.ErrorCode.RpcException;
import com.heartunderblade.rpc.RpcPojo.RpcRequest;
import com.heartunderblade.rpc.RpcPojo.RpcResponse;
import com.heartunderblade.rpc.factory.SerializerFactory;
import com.heartunderblade.rpc.service.Serializer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
@Slf4j
public class ProtocolMessageEncoderDecoder extends ByteToMessageCodec<ProtocolMessage<?>> {
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, ProtocolMessage<?> protocolMessage, ByteBuf byteBuf) throws Exception {
        //判断protocolMessage为空
        if(protocolMessage == null || protocolMessage.getHeader() == null){
            byteBuf.writeBytes(new byte[]{});
        }
        //得到请求头
        ProtocolMessage.Header header = protocolMessage.getHeader();

        //拼装请求
        //魔数 1字节
        byteBuf.writeBytes(new byte[]{header.getMagic()});


        //版本号 1字节
        byteBuf.writeBytes(new byte[]{header.getVersion()});
        //序列化器 1字节
        byteBuf.writeBytes(new byte[]{header.getSerializer()});
        //类型 1字节
        byteBuf.writeBytes(new byte[]{header.getType()});
        //状态 1字节
        byteBuf.writeBytes(new byte[]{header.getStatus()});
        //请求id 8字节
        byteBuf.writeLong(header.getRequestId());
        //消息体长度 4字节
//        byteBuf.writeInt(header.getBodyLength());
        // 获取序列化器
        ProtocolMessageSerializerEnum enumByKey = ProtocolMessageSerializerEnum.getEnumByKey(header.getSerializer());
        if(enumByKey == null){
            throw new RuntimeException("序列化协议不存在："+ enumByKey.getValue());
        }
        //利用key得到序列化器
        Serializer serializer = SerializerFactory.getInstance(enumByKey.getValue());
        //序列化请求体
        byte[] bodyBytes = serializer.serialize(protocolMessage.getBody());
        //写入请求体长度
        byteBuf.writeInt(bodyBytes.length);
        //写入请求体
        byteBuf.writeBytes(bodyBytes);
        //完成自定义协议编码
    }

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        // 分别从指定位置读出 Buffer
        ProtocolMessage.Header header = new ProtocolMessage.Header();
        //魔数
        byte magic = byteBuf.readByte();
        //校验魔数
        if(magic != ProtocolConstant.PROTOCOL_MAGIC){
//            throw new RuntimeException("消息 magic 非法" + magic);
            throw new RpcException(ErrorCode.ConsumerError,"消息 magic 非法" + magic);
        }
        //版本号
        byte version = byteBuf.readByte();
        //序列化器
        byte serializer = byteBuf.readByte();
        //类型
        byte type = byteBuf.readByte();
        //状态
        byte status = byteBuf.readByte();
        //请求id
        long RequestId = byteBuf.readLong();
        //消息体长度
        int BodyLength = byteBuf.readInt();
        //写入header
        header.setMagic(magic);
        header.setSerializer(serializer);
        header.setVersion(version);
        header.setType(type);
        header.setStatus(status);
        header.setRequestId(RequestId);

        header.setBodyLength(BodyLength);
        //获得请求体数据，以上一共17个字节
        byte[] bodyBytes = new byte[BodyLength];

        //写入请求体数据， 解决粘包问题，只读指定长度的数据
        byteBuf.readBytes(bodyBytes,0,BodyLength);
        //解析消息体
        // 获取序列化器
        ProtocolMessageSerializerEnum serializerEnum   = ProtocolMessageSerializerEnum.getEnumByKey(header.getSerializer());
        if(serializerEnum  == null){
        throw new RuntimeException("序列化消息的协议不存在");
        }
        //得到序列化器
        Serializer serializer1 = SerializerFactory.getInstance(serializerEnum .getValue());
        ProtocolMessageTypeEnum messageTypeEnum = ProtocolMessageTypeEnum.getEnumByKey(header.getType());
        if (messageTypeEnum == null) {
            throw new RuntimeException("序列化消息的类型不存在");
        }
        switch (messageTypeEnum) {
            case REQUEST:
                RpcRequest request  = serializer1.deserialize(bodyBytes, RpcRequest.class);
                list.add(new ProtocolMessage<>(header,request));
                return;
            case RESPONSE:
                RpcResponse response = serializer1.deserialize(bodyBytes, RpcResponse.class);
                list.add(new ProtocolMessage<>(header,response));
                return;
            case HEART_BEAT:return;
            case OTHERS:return;
            default:
                throw new RuntimeException("暂不支持该消息类型");
        }
    }


}
